package com.ruoyi.common.core.utils.sql;

import cn.hutool.core.util.ObjectUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.ruoyi.common.core.annotation.Query;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

@Slf4j
public class QueryHelp {
    public static <T, Q> MPJLambdaWrapper getPredicate(Class<?> entityClass, Q query ) {
        MPJLambdaWrapper<T> wrapper = new MPJLambdaWrapper<T>();
        if(query == null) {
            return wrapper;
        }
        try {
            wrapper.selectAll(entityClass);
            //获取全部属性
            List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
            for (Field field : fields) {
                boolean accessible = field.isAccessible();
                // 设置对象的访问权限，保证对private的属性的访
                field.setAccessible(true);
                Query q = field.getAnnotation(Query.class);
                if (q != null) {
                    //join字符串
                    String propName = q.propName();
                    Class<?> joinName = q.joinName();
                    String blurry = q.blurry();
                    String attributeName = isBlank(propName) ? field.getName() : propName;
                    //获取属性
                    Class<?> fieldType = field.getType();
                    Object val = field.get(query);
                    if ((ObjectUtil.isNull(val) || "".equals(val)) && joinName.getName().equals("java.lang.Object")) {
                        continue;
                    }

                    if (ObjectUtil.isNotEmpty(joinName) && !joinName.getName().equals("java.lang.Object")) {
                        wrapper.select(FuntionTools.getSFunction(joinName, field.getName()));
                        switch (q.join()) {
                            case LEFT:

                                wrapper.leftJoin(joinName, FuntionTools.getSFunction(joinName, field.getName()), FuntionTools.getSFunction(joinName, attributeName));
                                if(!ObjectUtil.isNull(val) && !"".equals(val)) {
                                    wrapper.eq(FuntionTools.getSFunction(joinName, field.getName()), val);
                                }
                                break;
                            case RIGHT:
                                wrapper.rightJoin(joinName, FuntionTools.getSFunction(joinName, field.getName()), FuntionTools.getSFunction(joinName, attributeName));
                                if(!ObjectUtil.isNull(val) && !"".equals(val)) {
                                    wrapper.eq(FuntionTools.getSFunction(joinName, field.getName()), val);
                                }
                                break;
                            case INNER:
                                wrapper.innerJoin(joinName, FuntionTools.getSFunction(joinName, field.getName()), FuntionTools.getSFunction(joinName, attributeName));
                                if(!ObjectUtil.isNull(val) && !"".equals(val)) {
                                    wrapper.eq(FuntionTools.getSFunction(joinName, field.getName()), val);
                                }
                                break;
                            default: break;
                        }
                    }
                    if(joinName.getName().equals("java.lang.Object")) {
                        switch (q.type()) {
                            case EQUAL:
                                wrapper.eq(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case GREATER_THAN:
                                wrapper.ge(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case LESS_THAN:
                                wrapper.le(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case LESS_THAN_NQ:
                                wrapper.lt(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case INNER_LIKE:
                                wrapper.like(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case LEFT_LIKE:
                                wrapper.likeLeft(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case RIGHT_LIKE:
                                wrapper.likeRight(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case IN:
                                wrapper.in(FuntionTools.getSFunction(entityClass, attributeName), (Collection<Object>)val);
                                break;
                            case NOT_IN:
                                wrapper.notIn(FuntionTools.getSFunction(entityClass, attributeName), ((Collection<Object>)val));
                                break;
                            case NOT_EQUAL:
//                            wrapper.not(FuntionTools.getSFunction(entityClass, attributeName), val));
                                break;
                            case NOT_NULL:
                                wrapper.isNotNull(FuntionTools.getSFunction(entityClass, attributeName));
                                break;
                            case IS_NULL:
                                wrapper.isNull(FuntionTools.getSFunction(entityClass, attributeName));
                                break;
                            case BETWEEN:
//                                String values =(String) val;
                                String[] values =  ((String) val).split(",");
//                                List<Object> between = new ArrayList<>((List<Object>)val);
                                if(values.length == 2){
//                                    wrapper.between(FuntionTools.getSFunction(entityClass, attributeName), between.get(0),between.get(1));
                                    wrapper.between(FuntionTools.getSFunction(entityClass, attributeName), values[0],values[1]);
                                }
                                break;
                            default: break;
                        }
                    }


                }
                field.setAccessible(accessible);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return wrapper;
    }


    public static <T, Q> MPJLambdaWrapper getPredicateEx( MPJLambdaWrapper<T> wrapper, Class<?> entityClass, Q query ) {
        if(query == null) {
            return wrapper;
        }
        try {
            wrapper.selectAll(entityClass);
            //获取全部属性
            List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
            for (Field field : fields) {
                boolean accessible = field.isAccessible();
                // 设置对象的访问权限，保证对private的属性的访
                field.setAccessible(true);
                Query q = field.getAnnotation(Query.class);
                if (q != null) {
                    //join字符串
                    String propName = q.propName();
                    Class<?> joinName = q.joinName();
                    String blurry = q.blurry();
                    String attributeName = isBlank(propName) ? field.getName() : propName;
                    //获取属性
                    Class<?> fieldType = field.getType();
                    Object val = field.get(query);
                    if ((ObjectUtil.isNull(val) || "".equals(val)) && joinName.getName().equals("java.lang.Object")) {
                        continue;
                    }

                    if (ObjectUtil.isNotEmpty(joinName) && !joinName.getName().equals("java.lang.Object")) {
                        wrapper.select(FuntionTools.getSFunction(joinName, field.getName()));
                        switch (q.join()) {
                            case LEFT:
                                /**
                                 * todo:链接修改测试
                                 */
//                                wrapper.leftJoin(joinName, FuntionTools.getSFunction(joinName, field.getName()), FuntionTools.getSFunction(joinName, attributeName));
                                if(!ObjectUtil.isNull(val) && !"".equals(val)) {
                                    wrapper.like(FuntionTools.getSFunction(joinName, attributeName), val);
                                }
                                break;
                            case RIGHT:
                                wrapper.rightJoin(joinName, FuntionTools.getSFunction(joinName, field.getName()), FuntionTools.getSFunction(joinName, attributeName));
                                if(!ObjectUtil.isNull(val) && !"".equals(val)) {
                                    wrapper.eq(FuntionTools.getSFunction(joinName, field.getName()), val);
                                }
                                break;
                            case INNER:
                                wrapper.innerJoin(joinName, FuntionTools.getSFunction(joinName, field.getName()), FuntionTools.getSFunction(joinName, attributeName));
                                if(!ObjectUtil.isNull(val) && !"".equals(val)) {
                                    wrapper.eq(FuntionTools.getSFunction(joinName, field.getName()), val);
                                }
                                break;
                            default: break;
                        }
                    }
                    if(joinName.getName().equals("java.lang.Object")) {
                        switch (q.type()) {
                            case EQUAL:
                                wrapper.eq(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case GREATER_THAN:
                                wrapper.ge(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case LESS_THAN:
                                wrapper.le(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case LESS_THAN_NQ:
                                wrapper.lt(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case INNER_LIKE:
                                wrapper.like(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case LEFT_LIKE:
                                wrapper.likeLeft(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case RIGHT_LIKE:
                                wrapper.likeRight(FuntionTools.getSFunction(entityClass, attributeName), val);
                                break;
                            case IN:
                                wrapper.in(FuntionTools.getSFunction(entityClass, attributeName), (Collection<Object>)val);
                                break;
                            case NOT_IN:
                                wrapper.notIn(FuntionTools.getSFunction(entityClass, attributeName), ((Collection<Object>)val));
                                break;
                            case NOT_EQUAL:
//                            wrapper.not(FuntionTools.getSFunction(entityClass, attributeName), val));
                                break;
                            case NOT_NULL:
                                wrapper.isNotNull(FuntionTools.getSFunction(entityClass, attributeName));
                                break;
                            case IS_NULL:
                                wrapper.isNull(FuntionTools.getSFunction(entityClass, attributeName));
                                break;
                            case BETWEEN:
                                String[] values =  ((String) val).split(",");
//                                List<Object> between = new ArrayList<>((List<Object>)val);
                                if(values.length == 2){
//                                    wrapper.between(FuntionTools.getSFunction(entityClass, attributeName), between.get(0),between.get(1));
                                    wrapper.between(FuntionTools.getSFunction(entityClass, attributeName), values[0],values[1]);
                                }
                                break;
                            default: break;
                        }
                    }


                }
                field.setAccessible(accessible);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return wrapper;
    }

    private static boolean isBlank(final CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    public static List<Field> getAllFields(Class clazz, List<Field> fields) {
        if (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            getAllFields(clazz.getSuperclass(), fields);
        }
        return fields;
    }
}
